(ns amsi.offer.offer
  (:require [amsi.common.logging :as  logger]))

(def msg-unique "Your offer is unique.")

(def msg-not-unique-no-unique "Your offer is not unique. There is no unique offer at the moment.")

(def msg-not-unique-less "Your offer is not unique. It is less than unique offer")

(def msg-not-unique-great "Your offer is not unique. It is great than unique offer")
                       
(defn min-offer
  "Compares 2 offers and returns min one"
  ([] nil)
  ([a b]
  (let[offer-value1 (:offer (val a)) offer-value2 (:offer (val b))]
    (if (< offer-value1 offer-value2)
      a
      b))))

(defn get-socket
  "Returns socket from streams map"
  [streams]
  (:socket (:streams streams)))

(defn process-unique-offer
  [out-queue unique-offers all-offers streams offer-value]
  "processing unique offer"
  (do
   (logger/log "processing unique offer")
   (.put @out-queue {:streams streams :message msg-unique})
   (alter unique-offers assoc offer-value {:streams streams :offer offer-value})
   (alter all-offers assoc offer-value 1)
   ))

(defn process-first-identical-offers
  "processing offer that is identical with unique offer"
  [out-queue unique-offers all-offers streams offer-value]
  (let [map-offer (get @unique-offers offer-value)]
    (logger/log "processing first identical")
    (alter unique-offers dissoc offer-value)
    (let[new-min-offer (reduce min-offer @unique-offers)]     
      (logger/log "new-min" (nil? new-min-offer))
      (cond        
        (nil? new-min-offer)        
        (do 
          (.put @out-queue {:streams streams :message msg-not-unique-no-unique})          
          (.put @out-queue {:streams (:streams map-offer) :message msg-not-unique-no-unique}))        
        :else  
        (let[message 
             (if (> (:offer (val new-min-offer)) offer-value)               
               msg-not-unique-less               
               msg-not-unique-great)]          
          (.put @out-queue {:streams streams :message message})
          (.put @out-queue {:streams (:streams map-offer) :message message}))))))

(defn process-identical-offers
  "processing identical offers"
  [out-queue unique-offers all-offers streams offer-value]
        (.put @out-queue {:streams streams :message msg-not-unique-no-unique}))          

(defn process-new-unique-offer
  "processing new unique offer"
  [out-queue unique-offers all-offers streams offer-value]
  (let[map-offer (reduce min-offer @unique-offers)]  
    (if ( < offer-value (:offer (val map-offer)))      
      (do 
        (.put @out-queue {:streams streams :message msg-unique})        
        (.put @out-queue {:streams (:streams (val map-offer) ) :message msg-not-unique-great}))      
      (.put @out-queue {:streams streams :message msg-not-unique-great}))    
    (alter unique-offers assoc  offer-value {:streams streams :offer offer-value})    
    (alter all-offers assoc offer-value 1)))

 (defn increment-all-counter
   "increments counter in all-offer map"   
   [all-offers offer-value]
   (alter all-offers assoc offer-value (+ 1 (get @all-offers offer-value))))  
 
(defn process-request1
  "processing user offer"
  [offer args]
  (logger/log "process called" @(:unique-offers args))    
  (let [offer-value (Double/parseDouble (:offer offer))
          out-queue (:out-queue args)
          unique-offers (:unique-offers args)
          all-offers (:all-offers args)
          streams (:streams offer)]
      (dosync  
        (cond          
          (and (empty? @unique-offers) (not(contains? @all-offers offer-value)));unique offer
          (do 
            (logger/log "it is min unique offer")
            (logger/log "map" @unique-offers)            
            (process-unique-offer out-queue unique-offers all-offers streams offer-value))  
          (and (contains? @unique-offers offer-value)(contains? @all-offers offer-value));unique offer is violated
          (do
            (logger/log "first identical offers processing")
            (increment-all-counter all-offers offer-value)              
            (logger/log "counter incremented")
            (process-first-identical-offers out-queue unique-offers all-offers streams offer-value))
          (and (empty? @unique-offers)(contains? @all-offers offer-value));offer is repeated. There is no unique offer at this moment.          
          (do           
            (logger/log "identical non unique offers processing")          
            (increment-all-counter all-offers offer-value)
            (process-identical-offers out-queue unique-offers all-offers streams offer-value))
          (and (not(contains? @unique-offers offer-value)) (not(contains? @all-offers offer-value)));new unique offer. Check is min unique offer.
          (do
            (logger/log "check for new")
            (process-new-unique-offer out-queue unique-offers all-offers streams offer-value))
          (:else) (println @unique-offers)))))
        

